package com.ebupt.migu.music.global.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ebupt.migu.globalpopup.entity.*;
import com.ebupt.migu.globalpopup.enums.FileTypeEnum;
import com.ebupt.migu.music.autoTri.Entity.PopupStatistics;
import com.ebupt.migu.music.common.entity.Page;
import com.ebupt.migu.music.common.entity.ResultObject;
import com.ebupt.migu.music.common.exception.MyException;
import com.ebupt.migu.music.common.exception.StatusEnum;
import com.ebupt.migu.music.common.util.DateUtil;
import com.ebupt.migu.music.global.dto.PriorityRequestBean;
import com.ebupt.migu.music.global.dto.QueryActivitiesResultBean;
import com.ebupt.migu.music.global.dto.RateActivityInfo;
import com.ebupt.migu.music.global.dto.RateMonitor;
import com.ebupt.migu.music.global.mapper.*;
import com.ebupt.migu.music.global.service.GlobalActionService;
import com.ebupt.migu.music.global.service.IH5InfoService;
import com.ebupt.migu.music.global.utils.TxtUtil;
import com.ebupt.migu.music.global.vo.PopupExportVo;
import com.ebupt.migu.music.global.vo.PopupVo;
import com.ebupt.migu.music.redis.service.RedisService;
import com.ebupt.migu.music.system.entity.SysUser;
import com.ebupt.migu.music.userGroup.mapper.CrowdMapper;
import com.ebupt.migu.restapi.DownloadByFtp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @Author liuyangyang@ebupt.com
 * @Description
 * @Date 2021/11/23 10:07
 */
@Slf4j
@Service
public class GlobalActionServiceImpl implements GlobalActionService {
    @Resource
    private ActionInfoMapper actionInfoMapper;
    @Resource
    private ActivityInfoMapper activityInfoMapper;
    @Resource
    private ConditionMapper conditionMapper;
    @Resource
    private PageInfoMapper pageInfoMapper;
    @Resource
    private PopupInfoMapper popupInfoMapper;
    @Resource
    private GlobalActionMapper globalActionMapper;
    @Resource
    private PageEnumMapper pageEnumMapper;
    @Resource
    private ActionTypeMapper actionTypeMapper;
    @Resource
    private RealTimeDataMapper realTimeDataMapper;
    @Autowired
    private IH5InfoService iH5InfoService;
    @Resource
    private GlobalActivityDetailMapper globalActivityDetailMapper;
    @Resource
    private DappChameleonEffectDataDMapper dappChameleonEffectDataDMapper;
    @Resource
    private AdsInfoMapper adsInfoMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private CrowdMapper crowdMapper;
    @Value("${path.file_ftp_path}")
    private String FILE_FTP_PATH;

    // 文件默认保存路径
    @Value("${path.file_global_path}")
    private String FILE_GLOBAL_PATH;

    @Value("${label.prefix}")
    private String labelPrefix;
    @Value("${label.post_url}")
    private String postUrl;

    /**
     * 创建弹窗活动
     *
     * @param user
     * @param bean
     * @return
     */
    @Override
    public ResultObject create(SysUser user, GlobalActionRequestBean bean) {
        ResultObject res = new ResultObject();
        String activityId = "GTC" + System.currentTimeMillis();
        log.info("活动ID:{}", activityId);
        boolean insert = insert(activityId, user, bean);
        if (!insert) {
            res.setCode(StatusEnum.ERROR.getCode());
            res.setMsg(StatusEnum.ERROR.getMsg());
            return res;
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }

    @Override
    public Boolean isHasAds(GlobalActionRequestBean bean) {
        if (Optional.ofNullable(bean.getAdsInfo()).isPresent()) {
            AtomicInteger i = new AtomicInteger(0);
            List<AdsInfo> adsInfos = adsInfoMapper.selectList(
                new QueryWrapper<AdsInfo>().lambda().eq(AdsInfo::getAdsScene, bean.getAdsInfo().getAdsScene())
                    .eq(AdsInfo::getIsCast, bean.getAdsInfo().getIsCast()));
            adsInfos.forEach(e -> {
                ActivityInfo ai = activityInfoMapper.selectOne(
                    new QueryWrapper<ActivityInfo>().lambda().eq(ActivityInfo::getActivityId, e.getActivityId())
                        .notIn(ActivityInfo::getActivityStatus, 6, 7, 9));
                if (ai != null && !bean.getActivityId().equals(ai.getActivityId())) {
                    i.incrementAndGet();
                }
            });
            return i.get() < 1;
        }
        return false;
    }

    /**
     * 更新弹窗活动
     *
     * @param user
     * @param bean
     * @return
     */
    @Override
    public ResultObject update(SysUser user, GlobalActionRequestBean bean) {
        ResultObject res = new ResultObject();
        String activityId = bean.getActivityId();
        if (StringUtils.isBlank(activityId)) {
            res.setCode(StatusEnum.BUSINID.getCode());
            res.setMsg(StatusEnum.BUSINID.getMsg());
            return res;
        }
        boolean delete = deleteByActivityId(activityId);
        boolean insert = insert(activityId, user, bean);
        if (!delete || !insert) {
            res.setCode(StatusEnum.ERROR.getCode());
            res.setMsg(StatusEnum.ERROR.getMsg());
            return res;
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }

    /**
     * 删除
     *
     * @param user
     * @param activityIds
     * @return
     */
    @Override
    public ResultObject delete(SysUser user, GlobalActionRequestBean activityIds) {
        ResultObject res = new ResultObject();
        if (null == activityIds.getActivityIds() || 0 == activityIds.getActivityIds().size()) {
            res.setCode(StatusEnum.BUSINID.getCode());
            res.setMsg(StatusEnum.BUSINID.getMsg());
            return res;
        }

        activityIds.getActivityIds().stream().forEach(activityId -> {
            // deleteByActivityId(activityId);
            logicalDeleteByActivityId(activityId);
            log.info("删除活动：{}", activityId);
        });
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }

    private void logicalDeleteByActivityId(String activityId) {
        iH5InfoService.untie(activityId);
        try {
            Integer status = 7;
            Long aLong = activityInfoMapper.updateStatusByactiveId(activityId, status);
            /*actionInfoMapper.delete(new QueryWrapper<ActionInfo>().lambda().eq(ActionInfo::getActivityId, activityId));
            activityInfoMapper.delete(new QueryWrapper<ActivityInfo>().lambda().eq(ActivityInfo::getActivityId, activityId));
            popupInfoMapper.delete(new QueryWrapper<PopupInfo>().lambda().eq(PopupInfo::getActivityId, activityId));
            pageInfoMapper.delete(new QueryWrapper<PageInfo>().lambda().eq(PageInfo::getActivityId, activityId));
            conditionMapper.delete(new QueryWrapper<ConditionRelation>().lambda().eq(ConditionRelation::getActivityId, activityId));
            globalActivityDetailMapper.delete(new QueryWrapper<GlobalActivityDetail>().lambda().eq(GlobalActivityDetail::getActivityId, activityId));*/
        } catch (Exception e) {
            log.error("删除活动失败：{}", e.getMessage());
        }
    }

    /**
     * 查询页面枚举
     *
     * @return
     */
    @Override
    public ResultObject<JSONArray> pageEnum(PageEnum page) {
        List<PageEnum> pageEnums = pageEnumMapper.selectList(new QueryWrapper<PageEnum>().lambda()
            .isNotNull(PageEnum::getId).eq(PageEnum::getActionType, page.getActionType())
            .apply(page.getPopupType() != null, "find_in_set('" + page.getPopupType() + "', popup_type)"));
        JSONArray enums = new JSONArray();
        pageEnums.forEach(pageEnum -> {
            JSONObject json = new JSONObject();
            json.put("pageKey", pageEnum.getPageKey());
            json.put("pageName", pageEnum.getPageName());
            json.put("actionType", pageEnum.getActionType());
            JSONArray children = new JSONArray();
            if (!StringUtils.isBlank(pageEnum.getResourceName())) {
                String[] name = pageEnum.getResourceName().split(",");
                String[] type = pageEnum.getResourceType().split(",");
                String[] message = pageEnum.getMessage().split("&");
                for (int i = 0; i < name.length; i++) {
                    JSONObject param = new JSONObject();
                    param.put("resourceType", type[i]);
                    param.put("resourceName", name[i]);
                    param.put("message", message[i]);
                    children.add(param);
                }
            }
            json.put("children", children);
            enums.add(json);
        });
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), StatusEnum.SUCCESS.getMsg(), enums);
    }

    /**
     * 调整活动优先级
     *
     * @param bean
     * @return
     */
    @Override
    public ResultObject priority(PriorityRequestBean bean) {
        ResultObject res = new ResultObject();
        // 临时ID
        Integer temp = globalActionMapper.maxID() + 999;
        // 提升优先级
        if (1 == bean.getPriority()) {
            Integer next = globalActionMapper.priorityUp(bean.getId());
            if (null == next) {
                res.setCode(StatusEnum.BUSINID.getCode());
                res.setMsg("当前活动已经具有最高优先级，无法提升");
                return res;
            }
            priorityChange(bean.getId(), next, temp);
        } else {
            Integer prev = globalActionMapper.priorityDown(bean.getId());
            if (null == prev) {
                res.setCode(StatusEnum.BUSINID.getCode());
                res.setMsg("当前活动已经是最低优先级，无法降级");
                return res;
            }
            priorityChange(bean.getId(), prev, temp);
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }

    @Override
    public ResultObject queryFile(Map<String, Object> params) {
        HashMap<Object, Object> map = new HashMap<>();
        String fileOriName = params.get("fileOriname").toString();
        String csv = ".csv";
        String fileName;
        // 如何传入文件名以.csv结尾，就不必拼接尾缀
        if (fileOriName.toLowerCase().endsWith(csv)) {
            fileName = fileOriName;
        } else {
            fileName = fileOriName + csv;
        }
        String filepath = FILE_FTP_PATH + fileName;
        // filepath = "D:\\apps\\fine-operation-label\\" + fileName; // 本地测试
        log.info("上传文件：{},路径：{}", fileName, filepath);
        File file = new File(filepath);
        if (!file.exists()) {
            throw new MyException(StatusEnum.FILE_NOT_EXISTS, "");
        }
        // 将文件内容读取出来
        TxtUtil txtUtil = TxtUtil.getTxtUtil();
        List data = txtUtil.toList(file);
        Set set = new HashSet(data);
        // 将内容存进redis，名字唯一性
        String uniqueName =
            DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS) + "-" + fileName;
        try {
            redisService.setManyValueSet(uniqueName, set);
        } catch (Exception e) {
            e.printStackTrace();
            // if (file.isFile() && file.exists()) {
            // boolean b = file.delete();
            // }
            return new ResultObject<>("1111", "读取失败", "");
        }
        map.put("uniqueName", uniqueName);
        map.put("fileSize", data.size());
        return new ResultObject<>("0000", "查询成功", map);
    }

    @Override
    public ResultObject<String> revocation(ActivityInfo activityInfo) {
        // 活动ID不可为空
        if (activityInfo.getActivityId() == null) {
            throw new MyException(StatusEnum.BUSINID, "活动ID不可为空");
        }
        // 活动状态不可为空
        Integer activityStatus = activityInfo.getActivityStatus();
        if (activityStatus == null) {
            throw new MyException(StatusEnum.BUSINID, "活动状态不可为空");
        }
        // 仅【1-待审核】状态下的弹窗可以撤回
        if (!activityStatus.equals(1)) {
            throw new MyException(StatusEnum.BUSINID, "当前活动不可撤回");
        }
        activityInfo
            .setRevocationTime(DateUtil.parseDateToStr(new Date(), DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
        try {
            activityInfoMapper.revocation(activityInfo);
        } catch (Exception e) {
            log.error("撤回活动失败", e);
            throw new MyException(StatusEnum.ERROR, "撤回活动失败");
        }
        return new ResultObject<String>("0000", "撤回成功", "已成功撤回该活动！");
    }

    @Override
    public ResultObject<Page<PopupVo>> queryMap(Map<String, Object> params) {
        // 验证是否为系统管理员或者业务管理员，业务管理员和系统管理员可以查看所有部门信息
        if ("1".equals(params.get("isAdmin").toString()) || "1".equals(params.get("isBSLAuditor"))
            || "1".equals(params.get("isSuperAdmin"))) {
            params.remove("creatorDepartment");
        }
        // 判断是查询明细还是汇总
        String summary = params.get("summary").toString();
        // 查询总条数
        Integer total =
            "1".equals(summary) ? activityInfoMapper.countSummary(params) : activityInfoMapper.countQuery(params);
        // 查询所有结果
        List<PopupVo> data =
            "1".equals(summary) ? activityInfoMapper.querySummary(params) : activityInfoMapper.queryMap(params);
        // 获取下发总数，判断下发总数是全量还是全量减去限制条件人数
        for (PopupVo d : data) {
            String totalNumber = d.getTotalNumber();
            if (totalNumber == null || Integer.parseInt(totalNumber) == 0) {
                List<ConditionRelation> conditionRelationList =
                    conditionMapper.selectList(new QueryWrapper<ConditionRelation>().lambda()
                        .eq(ConditionRelation::getActivityId, d.getActivityId()));
                if (conditionRelationList == null || conditionRelationList.size() == 0) {
                    d.setTotalNumber("全量");
                } else {
                    for (ConditionRelation conditionRelation : conditionRelationList) {
                        if (!conditionRelation.getPropertyCode().equals(2)) {
                            d.setTotalNumber("全量减去限制条件人数");
                            break;
                        }
                    }
                }
            }
        }
        // 分页
        Page<PopupVo> page = new Page<>();
        page.setTotal(total);
        page.setData(data);
        ResultObject<Page<PopupVo>> res = new ResultObject<>();
        res.setData(page);
        return res;
    }

    @Override
    public ResultObject qryByIdAndTime(Map<String, Object> params) {
        ResultObject res = new ResultObject<>();
        if (params.get("activityId") != null && params.get("qryDate") != null) {
            List<DappChameleonEffectDataD> ds =
                dappChameleonEffectDataDMapper.selectList(new QueryWrapper<DappChameleonEffectDataD>().lambda()
                    .eq(DappChameleonEffectDataD::getActivityId, params.get("activityId"))
                    .eq(DappChameleonEffectDataD::getDealDay, params.get("qryDate")));
            ds.forEach(e -> {
                // 将活动名称替换成策略名称
                PopupInfo popupInfo = popupInfoMapper.selectOne(
                    new QueryWrapper<PopupInfo>().lambda().eq(PopupInfo::getActivityCid, e.getActivityCid()));
                Optional.ofNullable(popupInfo).ifPresent(o -> e.setActivityName(o.getPopupName()));
            });
            res.setData(ds);
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }

    @Override
    public List<PopupExportVo> exportMap(Map<String, Object> params) {
        // 验证是否为超级管理员，超级管理员可以查看所有部门信息
        if ("1".equals(params.get("isAdmin").toString()) || "1".equals(params.get("isBSLAuditor"))) {
            params.remove("creatorDepartment");
        }
        // 判断是查询明细还是汇总
        String summary = params.get("summary").toString();
        List<PopupExportVo> datas =
            "1".equals(summary) ? activityInfoMapper.exportSummary(params) : activityInfoMapper.exportMap(params);
        for (PopupExportVo vo : datas) {
            String totalNumber = vo.getTotalNumber();
            if (totalNumber == null || Integer.parseInt(totalNumber) == 0) {
                List<ConditionRelation> conditionRelationList =
                    conditionMapper.selectList(new QueryWrapper<ConditionRelation>().lambda()
                        .eq(ConditionRelation::getActivityId, vo.getActivityId()));
                if (conditionRelationList == null || conditionRelationList.size() == 0) {
                    vo.setTotalNumber("全量");
                } else {
                    for (ConditionRelation conditionRelation : conditionRelationList) {
                        if (!conditionRelation.getPropertyCode().equals(2)) {
                            vo.setTotalNumber("全量减去限制条件人数");
                            break;
                        }
                    }
                }
            }
        }
        return datas;
    }

    @Override
    public ResultObject<Page<Map<String, Object>>> queryMinMap(Map<String, Object> params) {
        // 查询历史数据为type=1
        setMinQueryTime(params);
        // 查询总条数
        Integer total = realTimeDataMapper.countQuery(params);
        // 查询所有结果 PopupStatistics
        List<Map<String, Object>> data = realTimeDataMapper.queryMinMap(params);
        // 分页
        Page<Map<String, Object>> page = new Page<>();
        page.setTotal(total);
        page.setData(data);
        ResultObject<Page<Map<String, Object>>> res = new ResultObject<>();
        res.setData(page);
        return res;
    }

    @Override
    public List<HashMap<String, Object>> exportMinMap(Map<String, Object> params) {
        setMinQueryTime(params);
        return realTimeDataMapper.exportMinMap(params);
    }

    /**
     * 可视化查询
     * 
     * @param params
     * @return
     */
    @Override
    public ResultObject queryMinVisualViews(Map<String, Object> params) {
        log.info("变色龙实时数据可视化试图参数：{}", params.toString());
        String startTime = params.get("startTime").toString();
        String endTime = params.get("endTime").toString();
        String type = "0";
        if ("".equals(startTime) && "".equals(endTime)) {
            type = "1";
        }
        params.put("type", type);
        setMinQueryTime(params);
        log.info("变色龙实时数据可视化视图转换后，实际参数：{}", params.toString());
        List<String> createTimeLst = new ArrayList<>();// 横轴 时间
        List<Integer> realityCntsLst = new ArrayList<>();// 累计实际下发人数
        List<Integer> exposureTimesLst = new ArrayList<>();// 累计曝光次数
        List<Integer> exposureCntsLst = new ArrayList<>();// 累计曝光人数
        List<Integer> clickTimesLst = new ArrayList<>();// 累计点击次数
        List<Integer> clickCntsLst = new ArrayList<>();// 累计点击人数
        List<String> hitsTimesLst = new ArrayList<>();// 点击率（次数）
        List<String> hitsCntsLst = new ArrayList<>();// 点击率（人数）

        // 查询所有结果 PopupStatistics
        List<PopupStatistics> minData = realTimeDataMapper.queryMinVisualViews(params);
        log.info("变色龙实时数据-可视化试图查询数据库：{}", minData.toString());
        BigDecimal ad = null;
        BigDecimal bd = null;
        minData.forEach(a -> {
            createTimeLst.add(a.getCreateTime());
            realityCntsLst.add(a.getRealityCntsD());
            exposureTimesLst.add(a.getExposureTimesD());
            exposureCntsLst.add(a.getExposureCntsD());
            clickTimesLst.add(a.getClickTimesD());
            clickCntsLst.add(a.getClickCntsD());

            BigDecimal clTimes = new BigDecimal(Integer.parseInt(a.getClickTimesD() + ""));
            BigDecimal exTimes = new BigDecimal(Integer.parseInt(a.getExposureTimesD() + ""));
            BigDecimal clCnts = new BigDecimal(Integer.parseInt(a.getClickCntsD() + ""));
            BigDecimal exCnts = new BigDecimal(Integer.parseInt(a.getExposureCntsD() + ""));
            hitsTimesLst.add(ADivideBPercent(clTimes, exTimes));
            hitsCntsLst.add(ADivideBPercent(clCnts, exCnts));
        });
        Integer realityCnts = 0;// 累计实际下发人数
        Integer exposureTimes = 0;// 累计曝光次数
        Integer exposureCnts = 0;// 累计曝光人数
        Integer clickTimes = 0;// 累计点击次数
        Integer clickCnts = 0;// 累计点击人数
        String hitsTimes = "0.0%";// 点击率（次数）
        String hitsCnts = "0.0%";// 点击率（人数）

        PopupStatistics max = new PopupStatistics();
        PopupStatistics min = new PopupStatistics();
        if (minData.size() != 0) {
            min = minData.get(0);
            max = minData.get(minData.size() - 1);
            if ("1".equals(type)) {
                realityCnts = max.getRealityCntsM();// 累计实际下发人数
                exposureTimes = max.getExposureTimesM();// 累计曝光次数
                exposureCnts = max.getExposureCntsM();// 累计曝光人数
                clickTimes = max.getClickTimesM();// 累计点击次数
                clickCnts = max.getClickCntsM();// 累计点击人数
            } else {
                realityCnts = max.getRealityCntsM() - min.getRealityCntsM();// 累计实际下发人数
                exposureTimes = max.getExposureTimesM() - min.getExposureTimesM();;// 累计曝光次数
                exposureCnts = max.getExposureCntsM() - min.getExposureCntsM();;// 累计曝光人数
                clickTimes = max.getClickTimesM() - min.getClickTimesM();;// 累计点击次数
                clickCnts = max.getClickCntsM() - min.getClickCntsM();;// 累计点击人数
            }
            BigDecimal clTimes = new BigDecimal(Integer.parseInt(clickTimes + ""));
            BigDecimal exTimes = new BigDecimal(Integer.parseInt(exposureTimes + ""));
            BigDecimal clCnts = new BigDecimal(Integer.parseInt(clickCnts + ""));
            BigDecimal exCnts = new BigDecimal(Integer.parseInt(exposureCnts + ""));
            hitsTimes = ADivideBPercent(clTimes, exTimes);// 点击率（次数）
            hitsCnts = ADivideBPercent(clCnts, exCnts);// 点击率（人数）
        }

        List<Map<String, Object>> data = new ArrayList<>();
        String activityName = max.getActivityName() != null ? max.getActivityName() : "";
        Map actInfo = new HashMap<>();
        actInfo.put("type", "actInfo");
        actInfo.put("activityId", params.get("activityId"));
        actInfo.put("activityName", activityName);
        actInfo.put("realityCntsTotal", realityCnts);
        actInfo.put("exposureTimesTotal", exposureTimes);
        actInfo.put("exposureCntsTotal", exposureCnts);
        actInfo.put("clickTimesTotal", clickTimes);
        actInfo.put("clickCntsTotal", clickCnts);
        actInfo.put("hitsTimesTotal", hitsTimes);
        actInfo.put("hitsCntsTotal", hitsCnts);

        data.add(actInfo);

        Map createTimeMap = new HashMap<>();
        createTimeMap.put("type", "createTime");
        createTimeMap.put("list", createTimeLst);
        data.add(createTimeMap);

        Map realityCntsMap = new HashMap<>();
        realityCntsMap.put("type", "realityCnts");
        realityCntsMap.put("total", realityCnts);
        realityCntsMap.put("list", realityCntsLst);
        data.add(realityCntsMap);

        Map exposureTimesMap = new HashMap<>();
        exposureTimesMap.put("type", "exposureTimes");
        exposureTimesMap.put("total", exposureTimes);
        exposureTimesMap.put("list", exposureTimesLst);
        data.add(exposureTimesMap);

        Map exposureCntsMap = new HashMap<>();
        exposureCntsMap.put("type", "exposureCnts");
        exposureCntsMap.put("total", exposureCnts);
        exposureCntsMap.put("list", exposureCntsLst);
        data.add(exposureCntsMap);

        Map clickTimesMap = new HashMap<>();
        clickTimesMap.put("type", "clickTimes");
        clickTimesMap.put("total", clickTimes);
        clickTimesMap.put("list", clickTimesLst);
        data.add(clickTimesMap);

        Map clickCntsMap = new HashMap<>();
        clickCntsMap.put("type", "clickCnts");
        clickCntsMap.put("total", clickCnts);
        clickCntsMap.put("list", clickCntsLst);
        data.add(clickCntsMap);

        Map hitsTimesMap = new HashMap<>();
        hitsTimesMap.put("type", "hitsTimes");
        hitsTimesMap.put("total", hitsTimes);
        hitsTimesMap.put("list", hitsTimesLst);
        data.add(hitsTimesMap);

        Map hitsCntsMap = new HashMap<>();
        hitsCntsMap.put("type", "hitsCnts");
        hitsCntsMap.put("total", hitsCnts);
        hitsCntsMap.put("list", hitsCntsLst);
        data.add(hitsCntsMap);
        log.info("变色龙实时数据-可视化试图计算结果：{}", data.toString());
        ResultObject res = new ResultObject<>();
        res.setData(data);
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }

    /**
     * a / b 计算百分比
     * 
     * @param a
     * @param b
     * @return eg:65.32%
     */
    private String ADivideBPercent(BigDecimal a, BigDecimal b) {
        String percent = b == null ? "-" : b.compareTo(new BigDecimal(0)) == 0 ? "-"
            : a == null ? "0.00%" : a.multiply(new BigDecimal(100)).divide(b, 2, BigDecimal.ROUND_HALF_UP) + "%";
        return percent;
    }

    // 设置传参时间范围，type实时为1，历史数据为0
    private Map setMinQueryTime(Map<String, Object> params) {
        if (params.get("type").equals("1") || (params.get("type").equals("0") && params.get("startTime").equals("")
            && params.get("endTime").equals(""))) {
            if (params.get("type").equals("1")) {
                // 查询历史数据，即当天所有数据，不分名称和类型
                params.remove("activityName");
                params.remove("exeType");
            }
            Date curDate = new Date();
            Date startDate = DateUtil.getDayBeginTime(curDate);
            Date endDate = DateUtil.getDayEndTime(curDate);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String startTime = sdf.format(startDate);
            String endTime = sdf.format(endDate);

            params.put("startTime", startTime);
            params.put("endTime", endTime);
        }
        return params;
    }

    /**
     * 查询活动列表
     *
     * @param user
     * @param bean
     * @return
     */
    @Override
    public ResultObject select(SysUser user, QueryGlobalActionsRequestBean bean) {
        String userRole = user.getUserRole();
        ResultObject<Page<QueryActivitiesResultBean>> res = new ResultObject<>();
        try {
            // 如果不是审核人员，则只能查询自己创建的弹窗
            String[] roleArr = userRole.split(",");
            if (roleArr.length > 0) {
                List<String> roleList = Arrays.asList(roleArr);
                if (!roleList.contains("0") && !roleList.contains("5555")) {
                    bean.setCreatorDepartment(user.getDeptName());
                }
            }
            if (null != bean.getCurrent() && null != bean.getEvery()) {
                bean.setCurrent((bean.getCurrent() - 1) * bean.getEvery());
            }
            Integer total = globalActionMapper.queryTotal(bean);
            List<QueryActivitiesResultBean> data = globalActionMapper.query(bean);
            data.forEach(dataBean -> {
                // 将action type的枚举值映射为中文
                ActionType actionType = actionTypeMapper.selectOne(new QueryWrapper<ActionType>().lambda()
                    .eq(ActionType::getActionTypeValue, dataBean.getActionType()));
                dataBean.setActionTypeName(actionType.getActionTypeName());
                // 查询活动中关联的页面名称
                List<String> pageNames = new ArrayList<>();
                List<PageInfo> pageInfos = pageInfoMapper.selectList(
                    new QueryWrapper<PageInfo>().lambda().eq(PageInfo::getActivityId, dataBean.getActivityId()));
                pageInfos.forEach(pageInfo -> {
                    pageNames.add(pageInfo.getPageName());
                });
                dataBean.setPageNames(pageNames);
            });
            Page<QueryActivitiesResultBean> page = new Page<>();
            page.setTotal(total);
            page.setData(data);
            res.setCode(StatusEnum.SUCCESS.getCode());
            res.setMsg(StatusEnum.SUCCESS.getMsg());
            res.setData(page);
            return res;
        } catch (Exception e) {
            log.error("查询活动列表失败：{}", e.getMessage());
            res.setCode(StatusEnum.ERROR.getCode());
            res.setMsg(StatusEnum.ERROR.getMsg());
            return res;
        }
    }

    /**
     * 查询
     *
     * @param bean
     * @return
     */
    @Override
    public ResultObject selectById(QueryGlobalActionsRequestBean bean) {
        ResultObject res = new ResultObject();
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        QueryGlobalActionsResultBean data = globalActionMapper.queryById(bean);
        data.getPages().forEach(pageInfoResultBean -> {
            PageEnum pageEnum = pageEnumMapper.selectOne(
                new QueryWrapper<PageEnum>().lambda().eq(PageEnum::getPageName, pageInfoResultBean.getPageName())
                    .eq(PageEnum::getActionType, data.getActivity().getActionType()));
            String name = "";
            if (null != pageEnum.getResourceName() && pageEnum.getResourceName().split(",").length != 0) {
                String[] names = pageEnum.getResourceName().split(",");
                String[] types = pageEnum.getResourceType().split(",");
                int i = 0;
                for (String type : types) {
                    if (type.equals(pageInfoResultBean.getContentType())) {
                        name = names[i];
                        i++;
                    }
                }
            }
            pageInfoResultBean.setContentName(name);
        });
        data.setDetail(globalActivityDetailMapper.selectOne(new QueryWrapper<GlobalActivityDetail>().lambda()
            .eq(GlobalActivityDetail::getActivityId, bean.getActivityId())).getDetail());
        data.setPopups(popupInfoMapper
            .selectList(new QueryWrapper<PopupInfo>().lambda().eq(PopupInfo::getActivityId, bean.getActivityId())));
        res.setData(data);
        return res;
    }

    /**
     * 创建活动
     *
     * @param activityId
     * @param user
     * @param bean
     */
    public boolean insert(String activityId, SysUser user, GlobalActionRequestBean bean) {
        try {
            // 计算文件ftp人群总数
            AtomicLong totalNum = new AtomicLong(0);
            bean.getConditions().forEach(condition -> {
                if (null != condition.getConditionKey() && null != condition.getPropertyCode()
                    && null != condition.getRelation()) {
                    if (condition.getPropertyCode() == 2) {
                        switch (condition.getRelation()) {
                            case 1:
                                totalNum.incrementAndGet();
                                break;
                            case 7:
                                String filePath = FILE_GLOBAL_PATH + FileTypeEnum.FILE_TYPE_ENUM_TXT.getFile() + "/"
                                    + condition.getConditionData();
                                if (redisService.exists(filePath)) {
                                    totalNum.addAndGet(redisService.length(filePath));
                                }
                                break;
                            case 22:
                                String _phone = condition.getGroupId() + "-phone";
                                String _imei = condition.getGroupId() + "-imei";
                                String _uid = condition.getGroupId() + "-uid";
                                totalNum.addAndGet(redisService.length(_phone));
                                totalNum.addAndGet(redisService.length(_imei));
                                totalNum.addAndGet(redisService.length(_uid));
                                break;
                            case 24:
                                totalNum.addAndGet(redisService.length(condition.getConditionData()));
                            default:
                                break;
                        }
                    } else if (condition.getPropertyCode() == 12) {
                        totalNum
                            .addAndGet((long)crowdMapper.queryByGroupID(condition.getGroupId()).get("userGroupSize"));
                    }
                }
            });

            ActivityInfo activity = bean.getActivity();
            activity.setTotalNumber(totalNum.get());
            activity.setActivityId(activityId);
            // 测试类型跳过审核流程
            if (activity.getExeType().equals(0)) {
                activity.setActivityStatus(3);
            } else {
                activity.setActivityStatus(1);
            }
            activityInfoMapper.insert(activity);

            if (null != bean.getActivity().getIsPrimary() && 1 != bean.getActivity().getIsPrimary()) {
                ActionInfo action = bean.getAction();
                action.setActivityId(activityId);
                actionInfoMapper.insert(action);

                List<PageInfo> pages = bean.getPages();
                pages.forEach(page -> {
                    page.setActivityId(activityId);
                    pageInfoMapper.insert(page);
                });
            }

            if (!bean.getPopups().isEmpty()) {
                // 多文案配置
                if (bean.getPopups().size() > 1) {
                    AtomicInteger i = new AtomicInteger(1);
                    bean.getPopups().forEach(e -> {
                        e.setActivityId(activityId);
                        e.setActivityCid(activityId + "_" + i);
                        popupInfoMapper.insert(e);
                        i.getAndIncrement();
                    });
                } else {
                    // 单文案
                    PopupInfo popup = bean.getPopups().get(0);
                    Optional.ofNullable(popup).ifPresent(e -> {
                        e.setActivityId(activityId);
                        e.setActivityCid(activityId + "_0");
                        e.setIsDefault(1);
                        popupInfoMapper.insert(e);
                    });
                }
            }

            Optional.ofNullable(bean.getAdsInfo()).ifPresent(a -> {
                // 广告配置
                AdsInfo ads = bean.getAdsInfo();
                ads.setActivityId(activityId);
                adsInfoMapper.insert(ads);
            });

            if (bean.getActivity().getConditionStatus().equals(2)) {
                // 获取propertyCode为12的condition对象
                Optional<ConditionRelation> relation =
                    bean.getConditions().stream().filter(c -> c.getPropertyCode().equals(12)).findFirst();
                ConditionRelation conditionRelation = new ConditionRelation();
                if (relation.isPresent()) {
                    conditionRelation = relation.get();
                }
                // 判断人群是否属于标签平台，属于则读取人群信息存入redis
                String groupId = conditionRelation.getGroupId();
                HashMap<String, Object> groupInfo = crowdMapper.queryByGroupID(groupId);
                Integer isStaticCustomer = (Integer)groupInfo.get("isStaticCustomer");
                if (isStaticCustomer.equals(1)) {
                    String activityEnd = bean.getActivity().getActivityEnd();
                    long endTime =
                        DateUtil.parseStrToDate(activityEnd, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI).getTime();
                    // 结束时间 + 一天 - 当前时间 即为过期时间
                    long expireTime = (endTime + 86400L) - System.currentTimeMillis();
                    // 用户群属于标签平台，需要读取用户群文件并存入redis
                    // 如果key存在，判断过期时间是否比活动结束时间长，长则不改变，短则更新过期时间
                    if (redisService.exists(groupId + "-phone")) {
                        long expire = redisService.getExpire(groupId + "-phone");
                        if (expireTime > expire) {
                            redisService.updateKeyExpireTime(groupId + "-phone", expireTime);
                            redisService.updateKeyExpireTime(groupId + "-imei", expireTime);
                            redisService.updateKeyExpireTime(groupId + "-uid", expireTime);
                        }
                    } else {
                        // 不存在则连接标签平台服务器，读取文件内容，存入redis
                        // 获取手机号文件信息并存入redis
                        File msisdnFile = DownloadByFtp.getLabelUserGroupForGPush(groupId, activityId,
                            labelPrefix + postUrl, 1, bean.getActivity().getApproveName());
                        getGroupInfoToRedis(msisdnFile, groupId + "-phone", expireTime);
                        // 获取imei/idfa文件信息存入redis
                        File idfaFile = DownloadByFtp.getLabelUserGroupForGPush(groupId, activityId,
                            labelPrefix + postUrl, 2, bean.getActivity().getApproveName());
                        getGroupInfoToRedis(idfaFile, groupId + "-imei", expireTime);
                        // 获取uid文件信息存入redis
                        File uidFile = DownloadByFtp.getLabelUserGroupForGPush(groupId, activityId,
                            labelPrefix + postUrl, 3, bean.getActivity().getApproveName());
                        getGroupInfoToRedis(uidFile, groupId + "-uid", expireTime);
                    }

                }
                conditionRelation.setActivityId(activityId);
                conditionRelation.setConditionKey(1);
                conditionMapper.insert(conditionRelation);
            } else {
                bean.getConditions().forEach(condition -> {
                    if (null != condition.getConditionKey() && null != condition.getRelation()) {
                        condition.setActivityId(activityId);
                        conditionMapper.insert(condition);
                    }
                });
            }

            GlobalActivityDetail globalActivityDetail = new GlobalActivityDetail();
            globalActivityDetail.setActivityId(activityId);
            globalActivityDetail.setDetail(bean.getDetail());
            globalActivityDetailMapper.insert(globalActivityDetail);
            return true;
        } catch (Exception e) {
            log.error("创建活动失败：{}", e.getMessage());
            deleteByActivityId(activityId);
            return false;
        }
    }

    /**
     * 读取人群信息存入redis中
     *
     * @param file 文件信息
     * @param key redis的key
     * @param expireTime 过期时间
     */
    @Async
    void getGroupInfoToRedis(File file, String key, Long expireTime) {
        if (file != null && file.length() != 0) {
            Set<String> set = new HashSet<>();
            String str;
            try {
                BufferedReader br = new BufferedReader(new FileReader(file));
                while ((str = br.readLine()) != null) {
                    if (!"".equals(str)) {
                        set.add(str);
                    }
                }
                redisService.setCollectToRedis(key, set, expireTime);
                br.close();
            } catch (IOException e) {
                log.info("读取标签平台文件异常：{}", e.getMessage());
                throw new MyException(StatusEnum.FILE_NOT_EXISTS, "读取标签平台文件异常");
            }
        }
    }

    /**
     * 根据活动ID删除活动
     *
     * @param activityId
     */
    public boolean deleteByActivityId(String activityId) {
        iH5InfoService.untie(activityId);
        try {
            actionInfoMapper.delete(new QueryWrapper<ActionInfo>().lambda().eq(ActionInfo::getActivityId, activityId));
            activityInfoMapper
                .delete(new QueryWrapper<ActivityInfo>().lambda().eq(ActivityInfo::getActivityId, activityId));
            popupInfoMapper.delete(new QueryWrapper<PopupInfo>().lambda().eq(PopupInfo::getActivityId, activityId));
            pageInfoMapper.delete(new QueryWrapper<PageInfo>().lambda().eq(PageInfo::getActivityId, activityId));
            conditionMapper.delete(
                new QueryWrapper<ConditionRelation>().lambda().eq(ConditionRelation::getActivityId, activityId));
            globalActivityDetailMapper.delete(
                new QueryWrapper<GlobalActivityDetail>().lambda().eq(GlobalActivityDetail::getActivityId, activityId));
            adsInfoMapper.delete(new QueryWrapper<AdsInfo>().lambda().eq(AdsInfo::getActivityId, activityId));
            return true;
        } catch (Exception e) {
            log.error("删除活动失败：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 交换优先级
     *
     * @param current
     * @param next
     * @param temp
     */
    private void priorityChange(int current, int next, int temp) {
        // 将目标优先级提升到临时id
        HashMap<String, Integer> paramsTemp = new HashMap<>();
        paramsTemp.put("currentID", next);
        paramsTemp.put("priorityID", temp);
        globalActionMapper.updatePriority(paramsTemp);

        // 将当前优先级提升到目标优先级
        HashMap<String, Integer> paramsUp = new HashMap<>();
        paramsUp.put("currentID", current);
        paramsUp.put("priorityID", next);
        globalActionMapper.updatePriority(paramsUp);

        // 将临时优先级降级到当前优先级
        HashMap<String, Integer> paramsDown = new HashMap<>();
        paramsDown.put("currentID", temp);
        paramsDown.put("priorityID", current);
        globalActionMapper.updatePriority(paramsDown);
    }

    @Override
    public ResultObject<String> pauseActivity(ActivityInfo activityInfo) {
        String activityId = activityInfo.getActivityId();
        Integer activityStatus = activityInfo.getActivityStatus();
        if (activityId == null || activityStatus == null) {
            throw new MyException(StatusEnum.BUSINID, "活动参数异常，无法暂停");
        }
        if (!activityStatus.equals(4)) {
            throw new MyException(StatusEnum.BUSINID, "当前活动状态为" + activityStatus + "," + "不满足暂停条件");
        }
        try {
            UpdateWrapper<ActivityInfo> wrapper = new UpdateWrapper<>();
            wrapper.lambda().eq(true, ActivityInfo::getActivityId, activityId).set(ActivityInfo::getActivityStatus, 5);
            activityInfoMapper.update(activityInfo, wrapper);
        } catch (Exception e) {
            throw new MyException(StatusEnum.ERROR, "暂停失败：" + e.getMessage());
        }
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "暂停成功", "");
    }

    @Override
    public ResultObject<String> recoveryActivity(ActivityInfo activityInfo) {
        String activityId = activityInfo.getActivityId();
        Integer activityStatus = activityInfo.getActivityStatus();
        if (activityId == null || activityStatus == null) {
            throw new MyException(StatusEnum.BUSINID, "活动参数异常，无法恢复");
        }
        if (!activityStatus.equals(5)) {
            throw new MyException(StatusEnum.BUSINID, "当前活动状态为" + activityStatus + "," + "不满足恢复条件");
        }
        try {
            UpdateWrapper<ActivityInfo> wrapper = new UpdateWrapper<>();
            wrapper.lambda().eq(true, ActivityInfo::getActivityId, activityId).set(ActivityInfo::getActivityStatus, 4);
            activityInfoMapper.update(activityInfo, wrapper);
        } catch (Exception e) {
            throw new MyException(StatusEnum.ERROR, "恢复失败:" + e.getMessage());
        }
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "恢复成功", "");
    }

    @Override
    public ResultObject<String> frequency(ActivityFrequency frequencyMap) {
        // 得到缓存失效时间 到期日期的24:59:59减去当前存储的时间
        if (frequencyMap.getExeType().equals("1")) {
            Date currentTime = new Date();
            Date endDate = DateUtil
                .getDayEndTime(DateUtil.parseStrToDate(frequencyMap.getEndTime(), DateUtil.DATE_FORMAT_YYYY_MM_DD));
            Long expireTime = (endDate.getTime() - currentTime.getTime()) / 1000;
            log.info("系统管理员或超级管理员设置变色龙弹窗的【全局配置管理】");
            // 对象转换为Json字符串保存，这个set方法限定使用String类型
            if (expireTime > 0) {
                redisService.set("activityFrequencySwitch", JSON.toJSONString(frequencyMap), expireTime);
            }
            log.info("设置的弹窗次数：{},开始时间：{},结束时间：{},有效时间：{}", frequencyMap.getTimes(), frequencyMap.getStartTime(),
                frequencyMap.getEndTime(), expireTime);
        } else {
            redisService.deleteKeyByKey("activityFrequencySwitch");
            log.info("关闭变色龙弹窗的【全局配置管理】");
        }
        return new ResultObject<>(StatusEnum.SUCCESS.getCode(), "设置成功", "");
    }

    @Override
    public ResultObject<String> getfreStatus() {
        ResultObject res = new ResultObject();
        Object FrequencySet = redisService.get("activityFrequencySwitch");
        if (FrequencySet != null) {
            res.setData(FrequencySet);
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        log.info("获取变色龙弹窗的【全局配置管理】状态" + FrequencySet);
        return res;
    }

    /**
     * 根据创建人，查询上一次的转化率阈值监控配置
     *
     * @param creator
     * @return
     */
    @Override
    public ResultObject<HashMap<String, Object>> qrySettingsByCreator(String creator) {
        ResultObject res = new ResultObject();
        RateMonitor monitor = new RateMonitor();
        List<HashMap<String, Object>> settings = crowdMapper.qrySettingsByCreator(creator);
        if (null != settings && settings.size() > 0) {
            List<RateActivityInfo> rates = new ArrayList<>();
            for (HashMap<String, Object> setting : settings) {
                RateActivityInfo info = new RateActivityInfo();
                info.setActivityId(String.valueOf(setting.get("activityId")));
                info.setActivityName(String.valueOf(setting.get("activityName")));
                rates.add(info);
            }
            monitor.setInfos(rates);
            monitor.setCreator(String.valueOf(settings.get(0).get("creator")));
            monitor.setEmails(String.valueOf(settings.get(0).get("emails")));
            monitor.setOperate(Integer.parseInt(String.valueOf(settings.get(0).get("operate"))));
            monitor.setRate(String.valueOf(settings.get(0).get("rate")));
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        res.setData(monitor);
        return res;
    }

    /**
     * 创建或者更新转化率阈值监控配置
     *
     * @param monitor
     * @return
     */
    @Override
    public ResultObject<HashMap<String, Object>> upsertSettings(RateMonitor monitor) {
        ResultObject res = new ResultObject();
        crowdMapper.delSettingsByCreator(monitor.getCreator());
        if (null != monitor.getInfos() && monitor.getInfos().size() != 0) {
            for (RateActivityInfo info : monitor.getInfos()) {
                HashMap<String, Object> params = new HashMap<>();
                params.put("activityId", info.getActivityId());
                params.put("activityName", info.getActivityName());
                params.put("emails", monitor.getEmails());
                params.put("rate", monitor.getRate());
                params.put("operate", monitor.getOperate());
                params.put("creator", monitor.getCreator());
                crowdMapper.insertSettingsByCreator(params);
            }
        }
        res.setCode(StatusEnum.SUCCESS.getCode());
        res.setMsg(StatusEnum.SUCCESS.getMsg());
        return res;
    }
}